

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "esp_http_client.h"
#include <esp_tls.h>
#include <esp_crt_bundle.h>
#include <esp_sntp.h>
#include <nvs_flash.h>
#include "string.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "cJSON.h"

#define TX0_PIN GPIO_NUM_1
#define RX0_PIN GPIO_NUM_3

#define TX1_PIN GPIO_NUM_17
#define RX1_PIN GPIO_NUM_18

#define WIFI_SSID "CMCC-xfang"
#define WIFI_PASS "13880257043"

// #define WIFI_SSID "k60"
// #define WIFI_PASS "yan123456"
void uart_init();
void uart_read_task(void *pvParameters);
void uart_print(const char *str);


#define DEEPSEEK_URL "https://api.deepseek.com/chat/completions"
#define API_KEY "Bearer sk-edd3e8cd147d4d6fadaa7934d1a6306b" // 替换为你的 DeepSeek API Key

static const char *TAG = "ESP32";



// esp_http_client_handle_t  client;

int json_parse(char *json_data);
// 事件处理函数，用于处理HTTP事件
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    ESP_LOGI(TAG, "HTTP_EVENT: %d", evt->event_id);

    switch (evt->event_id)
    {
    case HTTP_EVENT_ON_DATA:
        // ESP_LOGI(TAG, "Http_rx: %d, %s", evt->data_len, (char *)evt->data);
        //json解析，解析完成直接打印
        json_parse((char *)evt->data);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
        ESP_LOGI(TAG, "%s", (char *)evt->data);
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
        break;

    case HTTP_EVENT_ERROR:
        ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    
    default:
        break;
    }
    return ESP_OK;
}


void http_init(void)
{
    esp_http_client_config_t config = {
        .url = "https://api.deepseek.com/chat/completions", // 替换为你的目标URL
        .event_handler = _http_event_handler,
        .crt_bundle_attach = esp_crt_bundle_attach, // 使用证书包
        .timeout_ms = 30000,                        // 设置超时时间
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_header(client, "Authorization", API_KEY);
}

int json_parse(char *json_data)
{
    //解析deepseek返回的数据
    char *ptr = strstr(json_data,"content");
    if (ptr == NULL){
        return -1;
    }
    ptr += strlen("content")+3;
    char *end_ptr = strstr(ptr,"}");
    if (end_ptr == NULL){
        return -1;
    }
    *end_ptr = '\0';

    ESP_LOGI(TAG, "content: %s", ptr);
    uart_print(ptr);
    return 0;

#if 0 
    cJSON *root = cJSON_Parse(json_data);
    if (root == NULL)
    {
        ESP_LOGE(TAG, "Error parsing JSON");
        return -1;
    }

    // char *str = cJSON_Print(root);
    // ESP_LOGE(TAG, "JSON: %s", str);

    cJSON *choices = cJSON_GetObjectItem(root, "choices");
    if (choices == NULL)
    {
        ESP_LOGE(TAG, "Error getting choices");
        cJSON_Delete(root);
        return -1;
    }

    cJSON *message = cJSON_GetArrayItem(choices, 0);
    if (message == NULL)
    {
        ESP_LOGE(TAG, "Error getting message");
        cJSON_Delete(root);
        return -1;
    }

    cJSON *content_item = cJSON_GetObjectItem(message, "content");
    if (content_item == NULL)
    {
        ESP_LOGE(TAG, "Error getting content");
        cJSON_Delete(root);
        return -1;
    }
    ESP_LOGE(TAG, "%s",content_item->valuestring);

    // strcpy(content, content_item->valuestring);

    cJSON_Delete(root);

#endif 
    return 0;
}




static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    if (event_id == WIFI_EVENT_STA_START)
    {
        esp_wifi_connect();
    }
    else if (event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        esp_wifi_connect();
        ESP_LOGI(TAG, "Retry connecting to the AP");
    }
    else if (event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
    }
}

void wifi_init_sta(void)
{
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&cfg);

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id);
    esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip);

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = WIFI_SSID,
            .password = WIFI_PASS,
        },
    };

    esp_wifi_set_mode(WIFI_MODE_STA);
    esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
    esp_wifi_start();
}



void http_post_task(void *pvParameters)
{
    char *data = (char *)pvParameters;

    esp_http_client_config_t config = {
        .url = "https://api.deepseek.com/chat/completions", // 替换为你的目标URL
        .event_handler = _http_event_handler,
        .crt_bundle_attach = esp_crt_bundle_attach, // 使用证书包
        .timeout_ms = 5000,                        // 设置超时时间
    };
    esp_http_client_handle_t  client = esp_http_client_init(&config);

    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_header(client, "Content-Type", "application/json");
    esp_http_client_set_header(client, "Authorization", API_KEY);

    esp_http_client_set_post_field(client, data, strlen(data));

    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %lld",
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
    }

    vTaskDelay(30000 / portTICK_PERIOD_MS);
    esp_http_client_cleanup(client);
    vTaskDelete(NULL);
}

void uart_init()
{
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };
    // uart_param_config(UART_NUM_0, &uart_config);
    // uart_driver_install(UART_NUM_0, 1024, 1024, 0, NULL, 0);
    // uart_set_pin(UART_NUM_0, TX0_PIN, RX0_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    uart_param_config(UART_NUM_1, &uart_config);
    uart_driver_install(UART_NUM_1, 1024, 0, 0, NULL, 0);
    uart_set_pin(UART_NUM_1, TX1_PIN, RX1_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
// 函数：uart_print
// 功能：通过UART发送字符串
// 参数：const char *str，要发送的字符串
void uart_print(const char *str)
{
    // 调用uart_write_bytes函数，通过UART_NUM_0发送字符串
    uart_write_bytes(UART_NUM_1, str, strlen(str));
}

int data2json(char *data, char *json_data)
{
    // 将data数据 组装成 deepseek 接口需要的json格式

    cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
        ESP_LOGE(TAG, "Failed to create root JSON object");
        return -1;
    }
    // 添加键值对
    cJSON_AddStringToObject(root, "model", "deepseek-chat");

    // 创建json数组
    cJSON *messages = cJSON_CreateArray();

    cJSON *msg_1 = cJSON_CreateObject();
    cJSON_AddStringToObject(msg_1, "role", "system");
    cJSON_AddStringToObject(msg_1, "content", "You are a helpful assistant.");

    cJSON *msg_2 = cJSON_CreateObject();
    cJSON_AddStringToObject(msg_2, "role", "user");
    cJSON_AddStringToObject(msg_2, "content", data);
    cJSON_AddItemToArray(messages, msg_1);
    cJSON_AddItemToArray(messages, msg_2);

    cJSON_AddItemToObject(root, "messages", messages);

    cJSON_AddBoolToObject(root, "stream", false);
    

    // 调试打印一下
    char *json_str = cJSON_Print(root);
    if (json_data == NULL)
    {
        ESP_LOGE(TAG, "Failed to print JSON object");
        cJSON_Delete(root);
        return -1;
    }
    strcpy(json_data, json_str);

    // ESP_LOGE(TAG, "JSON data: %s", json_data);

    // 释放内存
    cJSON_Delete(root);
    return 0;
}

void uart_read_task(void *pvParameters)
{
    char data[256]={0};
    char json_data[512]={0};
    while (1)
    {
       // uart_print("ready to read uart0：");        
        int len = uart_read_bytes(UART_NUM_1, data, sizeof(data) - 1, 20 / portTICK_PERIOD_MS);
        if (len > 0)
        {
            data[len] = '\0';
            ESP_LOGI(TAG, "uart_rx: %s", data);
            data2json(data, json_data);

            xTaskCreate(http_post_task, "http_post_task", 4096, (void *)json_data, 5, NULL);
        }
    }
}


// 同步时间（SNTP）
void sync_time(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "pool.ntp.org");
    sntp_init();

    time_t now = 0;
    struct tm timeinfo = {0};
    int retry = 0;
    const int retry_count = 100;

    while (timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count)
    {
        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        time(&now);
        localtime_r(&now, &timeinfo);
    }

    if (retry == retry_count)
    {
        ESP_LOGE(TAG, "Failed to get time from SNTP server");
    }
    else
    {
        timeinfo.tm_hour = timeinfo.tm_hour + 8; 
        ESP_LOGI(TAG, "Time synchronized: %s", asctime(&timeinfo));
    }
}

// 检查网络连接
bool check_network_connection(void)
{
    struct addrinfo hints = {0};
    struct addrinfo *res = NULL;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    int err = getaddrinfo("api.deepseek.com", "443", &hints, &res);
    if (err != 0 || res == NULL)
    {
        ESP_LOGE(TAG, "DNS lookup failed: %s", strerror(err));
        return false;
    }

    int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock < 0)
    {
        ESP_LOGE(TAG, "Failed to create socket");
        freeaddrinfo(res);
        return false;
    }

    if (connect(sock, res->ai_addr, res->ai_addrlen) != 0)
    {
        ESP_LOGE(TAG, "Failed to connect to server");
        close(sock);
        freeaddrinfo(res);
        return false;
    }

    close(sock);
    freeaddrinfo(res);
    ESP_LOGI(TAG, "Network connection check passed");
    return true;
}


void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    wifi_init_sta();
    uart_init();


    sync_time();
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    // 检查网络连接
    if (!check_network_connection())
    {
        ESP_LOGE(TAG, "Network connection check failed, aborting HTTPS request");
        return;
    }
    uart_print("uart tst\n");
    xTaskCreate(uart_read_task, "uart_read_task", 4096, NULL, 5, NULL);
}
